<!DOCTYPE html>
<html lang="zh-cn">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">




<title>高性能网站建设进阶指南 | Miles`s</title>

<link rel="stylesheet" href="https://mada.gitee.io/notes//css/styles.css">

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" 
integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>


<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/zenburn.min.css" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js" integrity="sha256-/BfiIkHlHoVihZdc6TFuj7MmJ0TWcWsMXkeDFwhi0zw=" crossorigin="anonymous"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="https://mada.gitee.io/notes//js/highlight.js"></script>






<div class="container">
    <nav class="navbar level">
      <div class="navbar-brand">
          <a class="nav-item" href="https://mada.gitee.io/notes/"><h1 class="title is-3">Miles`s</h1></a>
      </div>           
      <div class="navbar-menu has-text-centered is-active">
          <div class="navbar-end is-centered">
              
           </div>
      </div>
    </nav>
  </div>
<div class="container">
  <h2 class="subtitle is-6">November 13, 2016</h2>
  <h1 class="subtitle is-size-4-mobile is-size-3-desktop">高性能网站建设进阶指南</h1>
  <div class="content">
    

<p>《高性能网站建设指南》（2008）一书的跟进，其中提升性能的14条规则依旧适用，但网页内容和Web2.0应用程序的增长带来了一系列的性能挑战。</p>

<p>1－7章：JavaScript性能
8-12章：网络性能
13-14章：浏览器性能
最后提供一组好用的性能分析工具。</p>

<h1 id="第一章-理解ajax性能">第一章 理解Ajax性能</h1>

<h2 id="1-1-权衡">1.1 权衡</h2>

<p>计算机程序中，选择算法要权衡运行时间和内存，会为抢占市场而牺牲代码质量。</p>

<p>每一次接触代码，我们都在权衡改善代码质量和避免产生Bug的可能性。关注性能时，我们必须反复斟酌所有权衡因素。</p>

<h2 id="1-2-优化原则">1.2 优化原则</h2>

<p>目的：希望降低程序的整体开销，把重点放在对程序整体开销影响最大的部分。</p>

<p><img src="../../images/performance/main-rules.png" alt="main rules" /></p>

<h2 id="1-3-ajax">1.3 Ajax</h2>

<ol>
<li>采取正确的分工</li>
<li>数据包因该尽可能的小</li>
</ol>

<h2 id="1-4-浏览器">1.4 浏览器</h2>

<p>处理CSS依旧是最大的开销。理解DOM的奥秘并减少它的影响比试图给脚本提速效果更好。</p>

<h2 id="1-5-哇">1.5 哇！</h2>

<p>误用炫酷特性也会导致不必要的DOM操作，从而带来让人吃惊的巨大开销。</p>

<p>因该只在确定能改善用户体验时才使用，而不应用于炫耀或弥补功能与可用性上的缺陷。</p>

<h2 id="1-6-javascript">1.6 JavaScript</h2>

<p>大部分的JavaScript引擎的优化是为了快速抢占市场而不是性能。
通常情况下瓶颈不是JavaScript而是DOM。</p>

<p>避免使用那些传说中能让程序更快的奇淫技巧，除非你能证明它们将给应用带来明显的质量提升。</p>

<h2 id="1-7-总结">1.7 总结</h2>

<p>不要浪费时间去尝试那些不消耗大量时间的代码提速。
为质量编程。简洁、易读且条理分明的代码更易于正确理解、维护和优化。</p>

<h1 id="第二张-创建快速响应的web应用">第二张 创建快速响应的Web应用</h1>

<p>作者：Ben Galbraith和Dion Almaer</p>

<p>越来越多的网站在加载完成后，借助JavaScript来实现网页内容的动态更新。</p>

<p>当用户和浏览器交互时，操作系统接收到和计算机连接的各种设备，如键盘和鼠标的输入，在判断哪个应用因该接收这些输入之后，将它们打包为<strong>单独事件</strong>并放置到该应用的事件队列中。</p>

<p>浏览器处理这个过程实质上是单线程的。浏览器在执行页面的JavaScript期间无法响应其他的用户事件。因此，尽可能快的执行完页面中所有的Javascript是机器重要的。否则网页会非常缓慢甚至完全冻结。</p>

<p>Web Workers除外</p>

<h2 id="2-1-怎样才算足够快">2.1 怎样才算足够快</h2>

<p>Jakob Nielsen 问可用性领域知名且备受推崇的专家。论述足够快问题：
&gt; 基于Web应用的响应时间准则和所有其他应用一样。37年来这些准则毫无变化，所以它们也不太可能因新技术的出现而发生改变。
&gt;
&gt; 0.1秒：用户直接操作UI中对象的感觉极限。比如，从用户选择表格中的一列到该列高亮或向用户反馈已被选择的时间间隔。理想情况下，它也是对列进行排序的响应时间－－这种情况下用户会感到它们正在给表格排序。
&gt;
&gt; 1秒：用户随意地在计算机指令空间进行操作而无需过度等待的感觉极限。0.2～1.0秒的延迟意味着会被用户注意到，因此感觉到计算机处于对指令的“处理中”，这有别于直接响应用户的指令。例如：如果根据被选择的列对表格进行排序无法在0.1秒内完成，那么必须在1秒内完成，否则用户将感觉到UI变得缓慢且在执行任务中失去“流畅”的体验。超过1秒的延迟要提示用户计算机正在解决这个问题，例如改变光标的状态。
&gt;
&gt; 10秒：用户专注于任务的极限。超过10秒的任何操作都需要一个百分比完成指示器，以及一个方便用户中断操作且有清晰标识的方法，假设用户遭遇超过10秒延迟后才返回到原UI的情况，她们将需要重新适应。在用户的工作中，超过10秒的延迟仅在自然中断时可以接受，比如切换任务时。</p>

<p>综上所述，javascript执行超过0.1秒，页面将会给人不够平滑快捷的感觉；超过1秒，感到应用程序缓慢；超过10秒，那么用户非常沮丧。通过这些界定“足够快”的明确准则。</p>

<h2 id="2-2-测量延迟时间">2.2 测量延迟时间</h2>

<ol>
<li>手动检测： 添加计时器，在代码中加入特定代码来收集性能统计信息。</li>
<li>自动检测：例如：Firebug性能分析器。</li>
</ol>

<p><strong>观察者效应</strong>：观察代码性能的行为改变了代码的性能。造成正在测量的代码损失性能。</p>

<p>不过可以根据百分比的相对时间获得有用的信息作为参照。</p>

<h2 id="2-2-1-当延迟变得很严重时">2.2.1 当延迟变得很严重时</h2>

<p>如果JavaScript代码使浏览器线程停滞过长时间，大多数浏览器会进行干预并通过提示给用户中断执行代码的机会，不过还没有标准的行为规定浏览器该如何裁决是否给用户这个机会。</p>

<p>结论很简单：别把运行时间可能很长的低性能代码引入到网页中。</p>

<h2 id="2-3-线程处理">2.3 线程处理</h2>

<p>长时间运行的代码在另一个不同的线程上流畅地执行（由操作系统来负责保证浏览器用户界面线程和后台线程平等地共享计算机资源）</p>

<p>JavaScript并不支持多线程，尽量避免使用多线程。</p>

<h2 id="2-4-确保响应速度">2.4 确保响应速度</h2>

<h3 id="2-4-1-web-workers">2.4.1 Web Workers</h3>

<p>web worker api</p>

<pre><code class="language-js">var worker = new Worker(&quot;js/decrypt.js&quot;)
worker.onmessage = function(e){
	alert(&quot;The decrypted value is &quot; + e.data);
}
worker.postMessage(getValueToDecrypt());
</code></pre>

<p>js/decrypt.js中的内容:</p>

<pre><code class="language-js">onmessage = function(e){
	var valueToDecrypt = e.data
	
	postMessage(decryptedValue)
}
</code></pre>

<p>在页面上任何开销可能很大的javascript操作都应该托管给Worker。</p>

<h3 id="2-4-2-gears">2.4.2 Gears</h3>

<p>不支持web worker api 替代方案：Google的Gears插件</p>

<h3 id="2-4-3-定时器">2.4.3 定时器</h3>

<p>把运行时间很长的计算拆成独立的区块，然后使用javascript的定时器控制其执行。</p>

<h3 id="2-4-4-内存使用对响应时间的影响">2.4.4 内存使用对响应时间的影响</h3>

<p>垃圾回收（garbage collection GC）
自动内存管理是有开销的，当执行回收时，GC实现中最复杂的几乎是“stop the world”。它们会冻结整个运行环境，直到遍历完整个创建对象的“堆”。</p>

<p>大多数现代化的平台都提供了成熟的工具使你能够监控运行环境中GC进程的性能，但是javascript运行环境不可以。</p>

<h3 id="2-4-5-虚拟内存">2.4.5 虚拟内存</h3>

<p>如果网页的内存需求增长到足够大，可能会迫使操作系统开始内存分页，一个极慢的进程凭借迫使其他进程放弃其真正的内存来给浏览器不断增长的需求腾出空间－－分页。
分页会导致全面的无处不在的迟钝。</p>

<h3 id="2-4-6-内存问题的疑难解答">2.4.6 内存问题的疑难解答</h3>

<p>如果内存增长得比应用程序在使用过程中可忍受的大，那就需要检查代码，看看是否存在优化内存使用的可能性。</p>

<ul>
<li>使用delete关键字从内存中移除不再需要的javascript对象</li>
<li>从网页的DOM树上移除不再是必需的节点。</li>
</ul>

<p>2.5 总结</p>

<p>Ajax开创了一个持久运行且以javascript为中心的网页新时代。减少主进程上的运算来保持用户界面的快速响应。</p>

<p>Web Workers
gears
定时器
内存管理</p>

<h1 id="第三章-拆分初始化负载">第三章 拆分初始化负载</h1>

<h2 id="3-1-全部加载">3.1 全部加载</h2>

<p>想弄清楚在初始化页面时有多少javascript是必须加载的也是非常困难的。</p>

<p>在初始化时只加载必要的javascript，其余的稍后加载</p>

<p>问题：
* 能节省多少时间？
* 如何找到需要拆分的代码？
* 怎样处理竞争状态？
* 如何延迟加载“其余部分”的代码？</p>

<h2 id="3-2-通过拆分来节省下载量">3.2 通过拆分来节省下载量</h2>

<p>onload后加载（post-onload download）
其他不同的延迟方式。</p>

<h2 id="3-3-寻找拆分">3.3 寻找拆分</h2>

<p><strong>doloto</strong> 微软研究院开发的自动拆分JavaScript代码的系统。
它可以把代码拆分到不同的组
第一组初始化网页所需要的函数
剩下的按需加载。</p>

<h2 id="3-4-未定义标识符和竞争状态">3.4 未定义标识符和竞争状态</h2>

<p>javascript执行时引用到一个被降级到延迟加载的标志符，会出错。
竞争状态：用户先触发还是javascript先下载执行完。</p>

<h2 id="第四章-无阻塞加载脚本">第四章 无阻塞加载脚本</h2>

<h2 id="4-1-并行下载">4.1 并行下载</h2>

<p>ie8是第一个支持外部脚本并行下载的浏览器。
执行顺序的竞争状态。</p>

<h2 id="4-2-让脚本运行得更好">4.2 让脚本运行得更好</h2>

<p>既拥有外部脚本的好处，又能避免阻塞导致的减速方法：
* XHR Eval
* XHR注入
* Script in Iframe
* Script DOM Element
* Script Defer
* document.write Script Tag</p>

<p><strong>XHR Eval</strong></p>

<p>通过<strong>XMLHttpRequest（XHR）</strong>从服务器获取脚本，让响应完成时通过eval命令执行内容。</p>

<p>必须部署在和主页面相同的域中。</p>

<p><strong>XHR 注入</strong></p>

<p>通过<strong>XMLHttpRequest</strong>来获取javascript。然后创建一个script的DOM元素。注入script执行javascript。这种机制会比eval慢一点，有dom操作等。</p>

<p><strong>script in iframe</strong></p>

<p>iframe开销最高的dom元素。</p>

<p><strong>script dom element</strong></p>

<pre><code class="language-js">var scriptEle = document.createElement('script')
scriptEle.src=&quot;http://dss.com/a.js&quot;
document.getElements.ByTagName('head')[0].appendChild(scriptEle)
</code></pre>

<p>下载过程中，这种方式创建脚本不会阻塞其他组件</p>

<p>外部脚本可以直接调用。</p>

<p><strong>script defer</strong></p>

<p>当脚本中不包含对document.write的调用，且当前页面中没有其他脚本依赖于它，使用改属性是安全的。</p>

<p>允许其他资源并行下载</p>

<p>补充：浏览器解析到该属性时，继续向下解析，不阻塞文档，同时开始下载脚本，但是下载完不会立即执行，当文档解析完之后，开始执行脚本。
<strong>defer是有序的</strong>，当多个脚本使用该属性时可以顺序执行。</p>

<p><strong>document.write script tag</strong></p>

<p><code>document.write(&quot;&lt;script src='a.js'&gt;&lt;\/script&gt;&quot;)</code></p>

<p>下载脚本时，浏览器仍然阻塞其他类型资源。</p>

<p><strong>另外，还有html5的async属性</strong>
提供异步下载，下载完之后，停止解析文档，脚本，与defer相反，async会立即执行。
且async是无序的。</p>

<h2 id="4-3-浏览器忙指示器">4.3 浏览器忙指示器</h2>

<p>浏览器提供多种忙指示器：状态栏，进度条，标签页图标和光标。</p>

<h2 id="4-4-确保-或避免-按顺序执行">4.4 确保（或避免）按顺序执行</h2>

<p>根据是否有序决定使用的方法。</p>

<p><img src="../../images/performance/script-order.png" alt="script order" /></p>

<h1 id="第五章-整合异步脚本">第五章 整合异步脚本</h1>

<p>当异步加载的外部脚本与行内脚本之间存在代码依赖时，我们必须通过一种保证顺序的方法来整合这两个脚本。</p>

<h2 id="5-1-代码示例-menu-js">5.1 代码示例 menu.js</h2>

<p>一个外部脚本和一段行内脚本。
行内脚本依赖外部脚本，所以保证执行顺序至关重要－－外部脚本必须在行内脚本之前下载，解析和执行。</p>

<p>问题：如何异步加载外部js而又不让行内脚本产生未定义标识符错误</p>

<h2 id="5-2-竞争状态">5.2 竞争状态</h2>

<h2 id="5-3-异步加载脚本时保持执行顺序">5.3 异步加载脚本时保持执行顺序</h2>

<p>当外部脚本按照常规方法加载时，它会阻塞行内代码的执行，竞争状态不回发生。
一旦开始异步加载，就需要一种技术把行内代码和依赖行内代码的外部脚本整合起来。
* 硬编码回调
* Window Onload
* 定时器
* Script Onload
* Degrading Script Tags</p>

<p><code>Script Onload</code> 可能时最好的选择。</p>

<h3 id="5-3-1-硬编码回调">5.3.1 硬编码回调</h3>

<p>往往不太可能把回调嵌入第三方javascript模块中。</p>

<h3 id="5-3-2-技术2-window-onload">5.3.2 技术2: window onload</h3>

<p>缺点：
1. 得确认异步脚本是通过阻塞onload事件的方式加载的
2. 可能会导致行内代码延迟执行</p>

<h3 id="5-3-3-技术3-定时器">5.3.3 技术3:定时器</h3>

<p>不可控，如果menu.js加载失败，设置时间太大 或者太小都会产生不必要的问题。</p>

<h3 id="5-3-4-技术4-script-onload">5.3.4 技术4: Script Onload</h3>

<p>通过监听脚本<strong>onload</strong>事件解决了所有这些问题</p>

<p>加入<strong>script</strong>元素的onload和<strong>onreadystatechange</strong>事件处理程序，都设置为调用init函数。</p>

<pre><code class="language-js">var domscript = document.createElement('script')
domscript.src = &quot;menu.js&quot;
domscript.onloadDone = false
domscript.onload = function(){
	domscript.onloadDone = true
	init()
}

domscript.onreadystatechange = function(){
	if((&quot;loaded&quot;=== domscript.readyState || &quot;complete&quot; === domscript.readyState) &amp;&amp; !domscript.onloadDone){
	domscript.onloadDone = true
	init()
}
document.getElementsByTagName('head')[0].appendChild(domscript)
</code></pre>

<p><strong>script onload技术是整合异步加载外部脚本和行内脚本的首选。</strong> 行内代码可以在脚本加载完之后立即执行。事件处理也非常简单。</p>

<h3 id="5-3-5-技术5-降级使用script标签">5.3.5 技术5:降级使用script标签</h3>

<pre><code class="language-js">&lt;script src=&quot;jquery.js&quot; type=&quot;text/javascript&quot;&gt;
$('p').addClass('pretty')
&lt;/script&gt;
</code></pre>

<p>这个想法让行内代码在外部脚本加载成功之后执行。
优点：</p>

<p><strong>更干净</strong>
只有一个script标签
<strong>更清晰</strong>
行内代码对外部脚本的依赖更一目了然
<strong>更安全</strong>
如果外部代码失败，行内代码不会执行。</p>

<p>缺点：浏览器支持性差</p>

<p>解决方法：在外部脚本中添加代码。解析内部自己script标签，执行innerHTML。</p>

<pre><code class="language-js">var scripts = document.getElementsByTagName('script')
var cntr = scripts.length
while(cntr){
	var curScript = scripts[cntr-1]
	if(-1 != curScript.src.indexOf('outerScript.js')){
		eval(curScript.innerHTML);
		break;
	}
}
</code></pre>

<p>这个方法所有浏览器都正常运行。
然而，外部脚本并非异步加载的。</p>

<p>为了解决脚本的阻塞问题，需要把其中一种异步加载技术和该模式结合起来。</p>

<h2 id="5-4-多个外部脚本">5.4 多个外部脚本</h2>

<p>问题：解决并行加载外部脚本同时还能保持执行顺序。</p>

<h3 id="5-4-1-managed-xhr">5.4.1 Managed XHR</h3>

<p>使用队列，同时请求脚本。</p>

<p>解决了跨主流浏览器的兼容性问题。但是由于XHR的同源规则，如果外部脚本部署在与主页面不同的域下，该技术就无法工作。
使用DOM Element和Doc Write技术</p>

<h3 id="5-4-2-dom-element和doc-write">5.4.2 DOM Element和Doc Write</h3>

<p>异步加载跨域脚本3种方法：
* Script DOM Element
* Script Defer
* document.write Script Tag</p>

<p>结论：
没有简单的跨浏览器方案可以异步加载多个脚本，并且保持执行顺序。把所有脚本整合到一个单独的脚本中是一个值得考虑的选择。</p>

<h2 id="5-5-综合解决方案">5.5 综合解决方案</h2>

<h3 id="5-5-1-单个脚本">5.5.1 单个脚本</h3>

<p>最佳技术：Script DOM Element。</p>

<p>Script Onload模式是用于整合行内代码和单个外部脚本的最好选择。</p>

<h3 id="5-5-2-多个脚本">5.5.2 多个脚本</h3>

<p>浏览器差异</p>

<h2 id="5-6-实现互联网中的异步加载">5.6 实现互联网中的异步加载</h2>

<p>示例</p>

<h3 id="5-6-1-google分析和dojo">5.6.1 Google分析和Dojo</h3>

<h3 id="5-6-2-yui-loader">5.6.2 YUI Loader</h3>

<h1 id="第六章-布置行内脚本">第六章 布置行内脚本</h1>

<p>行内脚本不会产生额外的HTTP请求，但会阻塞页面上资源的并行下载，还会阻塞逐步渲染。</p>

<h2 id="6-1-行内脚本阻塞并行下载">6.1 行内脚本阻塞并行下载</h2>

<p>除了阻塞并行下载，行内脚本还阻塞渲染
解决方法：
* 把行内脚本移至底部
* 使用异步回调启动javascript
* 使用script的defer属性</p>

<h3 id="6-1-1-把行内脚本移至底部">6.1.1 把行内脚本移至底部</h3>

<p>虽然可以避免阻塞下载但是依旧阻塞渲染。如果脚本执行时间长的话，可以使用下面两种方法。</p>

<h3 id="6-1-2-异步启动执行脚本">6.1.2 异步启动执行脚本</h3>

<p>设置<strong>setTimeout(0)</strong>,额外的好处，在IE中实现了逐步渲染。
不阻塞文档渲染。</p>

<h3 id="6-1-3-使用defer属性">6.1.3 使用defer属性</h3>

<p>与把javascript访问文档底部类似。</p>

<h2 id="6-2-保持css和javascript的执行顺序">6.2 保持CSS和javascript的执行顺序</h2>

<p>CSS：有级联特性。
javascript：执行依赖</p>

<h3 id="6-3-2-样式表阻塞行内脚本">6.3.2 样式表阻塞行内脚本</h3>

<p><strong>在样式表后面的行内脚本会阻塞所有后续资源的下载</strong></p>

<p>调整行内脚本的位置，使其不出现在样式表和任何其他资源之间。</p>

<p>比较好的方法：将行内脚本放置在可见资源（图片）之后，以避免阻碍哀怨的下载。</p>

<h1 id="第七章-编写高效的javascript">第七章 编写高效的JavaScript</h1>

<p>关注性能，不仅要关注页面的加载时间，也要关注在页面上操作时的响应速度。要实现快速而友好的用户界面，最好的办法是编写的JavaScript代码能在所有浏览器中最高效地执行。</p>

<p>在性能优化上没有银弹，也没有一种方法能适用于100%的情况，自由结合各种技术，才能实现最大程度的性能优化。</p>

<h1 id="第十章-图像优化">第十章 图像优化</h1>

<p>作者： Stoyan Stefanov和Nicole Sullivan</p>

<p>图像优化是最易实施的方案。通常，我们可以在只有轻微质量损耗和无损的前提下大幅减小图像的大小。</p>

<p><img src="../../notes/images/performance/image-percent.png" alt="image percent" /></p>

<p>本章的重点是<strong>无损优化</strong>，在不损耗质量的前提下，将文件的大小减到最小。就算精确到像素级别，优化后的图像和原图在视觉质量上也是一样的。
移除元数据，对颜色或像素信息进行更好的压缩，以及删除对Web显示没有必要的快信息（针对png的情况）是减小图像大小的常用方法。</p>

<p>内容包括：
* Web上不同图像格式的特征（gif、jpeg和png）
* 自动化无损压缩
* AlphaImageLoader滤镜
* 优化Sprite
* 其他图像优化技术</p>

<h2 id="10-1-两步实现简单图像优化">10.1 两步实现简单图像优化</h2>

<ol>
<li>优化之前，首先要确定图像的颜色数、分辨率和清晰度。对这几个参数的修改<strong>有损优化</strong>，同时也会影响整个图像的质量。图像也许可以拥有更少的颜色，对于jpeg格式图像来说，可能意味着减少图像的编码。对哟jpeg图像来说，虽然60%~70%的质量是公认的标准，但确实有些图像或背景需要更高或更低质量。如何选择，根据具体设计师的创意来决定。具体的方法可以通过工具来实现。设计师同样可以使用空间压缩或区域压缩，比如，人像部分使用80%压缩，背景部分使用30%质量</li>
<li>一旦决定了需要什么质量的图像，就可以利用<strong>无损压缩技术</strong>尽可能减小图像的大小。使用自动化工具，自动优化。</li>
</ol>

<h2 id="图像格式">图像格式</h2>

<p>在web中广泛使用的3种图像格式－jpeg、png和gif（如今格式更多，且伴随着浏览器的兼容性问题。webp、apng、jpeg－2000、svg等）</p>

<h3 id="10-2-1背景">10.2.1背景</h3>

<p><strong>图形</strong></p>

<p>网站的logo、草图、图表、大部分动画和图标都属于图形。这些图像通常由连续的线条或其他尖锐的颜色过渡组成，颜色数量相对较少。</p>

<p><strong>照片</strong></p>

<p>通常由百万数量级的颜色，并且包含平滑的颜色过渡和渐变。</p>

<p>就格式而言</p>

<p>gif－显示图形
jpeg-更适合照片
png－两者都适合</p>

<p><strong>像素和RGB</strong></p>

<p>图像由像素组成，是图像中最小的信息单元。RGB颜色模型是最常用的一种
采用红（R），绿（G）和蓝（B）的数量多少的方式来描述一个像素。</p>

<p>将不同强度的成分组合在一起，就可以获得不同的颜色。</p>

<p><strong>真彩色图像VS调色板图像格式</strong></p>

<p>真彩色图像：256*256*256可以得到16777216种注册。可以支持着么多颜色的图像格式叫做真彩色图像格式；比如jpeg和真彩色类型的png</p>

<p>为了存储图像信息时节省一些空间，有一项技术是将图像中各种颜色提取出来建立一个表，这个表通常叫做调色板（也可以成为索引）。有了这个颜色表，就可以通过将调色板中的条目和每个像素重新匹配，达到重新绘制整个图像的目的。</p>

<p>调色板可以包含人意RGB颜色值，但是最经常使用的调色板格式－gif和png8-会限制最多256种。
你可以从1600+万的颜色中选择你需要的值，但是当个图像中最多只能抱憾256种颜色。</p>

<p><strong>透明和alpha通道（RGBA）</strong></p>

<p>在RGB的基础上做了扩展。额外的成分A表示透明，0～255值。实际上不同的程序会定义为0%~100%,或者从0~127的值。</p>

<p><strong>隔行扫描</strong></p>

<p>当网速很慢时，大图像会随着下载的进度逐行显示，从上到下每次显示一行，缓慢地向下递进。为了提高用户体验，部分图像进行<strong>隔行扫描</strong>.让用户在完整的下载图像之前，看到图像的一个粗略的版本。</p>

<h3 id="10-2-2-不同图像格式的特性">10.2.2 不同图像格式的特性</h3>

<p><strong>gif</strong>
是一种调色板图像
允许一个二进制类型的透明度。每个像素要么是透明，要么是完全不透明
支持动画
无损，也就是说你可以打开任意一个gif文件，做一些修改，保存关闭时不会损失任何质量。
支持可选的隔行扫描</p>

<p>适合显示图形，png8是用来显示图形的最佳格式。所以，只需要使用动画时才应该使用gif。</p>

<p><strong>jpeg</strong></p>

<p>是照片存储的实际标准。考虑到人类眼睛对颜色和光线强弱的感知，这种格式通过各种技术来减少图片所需要的信息，所以它能在经过高度压缩的文件中存储高分辨率的图像。</p>

<p>有损：用户可以设置自定义的质量级别，质量从0-100，但是就算设置为100，同样会有一定程度的质量损耗。</p>

<p>Note：当对某个图像进行多项编辑操作时，最好使用无损的图像格式来保存中间结果。</p>

<p>也有少数操作是无损的：
* 旋转（90度，180度和270度的情况下）
* 裁剪
* 翻转（水平或者垂直）
* 从标准模式切换到渐进模式，反之亦然
* 编辑图像元数据</p>

<p>不支持透明或动画
Progressive JPEG支持隔行扫描</p>

<p><strong>png</strong></p>

<ul>
<li>真色彩和调色板png格式：大致分为两种。</li>
<li>透明：</li>
<li>动画：暂不支持</li>
<li>无损</li>
<li>逐行扫描</li>
<li>隔行扫描</li>
</ul>

<h3 id="png的更多资料">png的更多资料</h3>

<p>png8（调色板）、png24（真色彩不支持alpha）和png32（真色彩支持alpha）</p>

<h2 id="自动无损图像优化">自动无损图像优化</h2>

<ul>
<li>优化png格式的图像</li>
<li>剥离jpeg中的元数据</li>
<li>将静态gif转化为png格式</li>
<li>对gif动画进行优化</li>
</ul>

<h3 id="10-3-1-优化png格式的图像">10.3.1 优化png格式的图像</h3>

<p>将png格式图像信息保存在<strong>块</strong>中。这种方式有利于扩张。但是对于web显示来说，大部分的块都非必要，我们要安全的删除。</p>

<p><strong>Pngcrush</strong>
<strong>pngout</strong>
<strong>optiPNG</strong>
跨平台，开源，通过命令行调用
<strong>pngOptimizer</strong>
<strong>PNGslim</strong>
windows的批处理文件，</p>

<h3 id="10-3-2-剥离jpeg的元数据">10.3.2  剥离jpeg的元数据</h3>

<ul>
<li>注释</li>
<li>应用程序定义的内部信息</li>
<li>exif信息：相机型号，日期，位置，缩略图等</li>
</ul>

<p>这些元数据不回影响图像显示，可以移除。
<strong>jpegtran</strong></p>

<h3 id="10-3-3-将gif转换成png">10.3.3 将gif转换成png</h3>

<p><strong>ImageMagick</strong></p>

<h3 id="10-3-4-优化gif动画">10.3.4 优化gif动画</h3>

<p><strong>Gifsicle</strong></p>

<h3 id="10-3-5-smush-it">10.3.5 Smush.it</h3>

<p><a href="http://smush.it">在线图像优化工具</a>,有本书作者开发。</p>

<p>10.3.6 使用渐进jpeg格式来存储大图像</p>

<h2 id="10-4-alpha透明-避免使用alphaimageloader">10.4 Alpha透明：避免使用AlphaImageLoader</h2>

<p>老版本IE</p>

<h3 id="10-4-1-alpha透明度效果">10.4.1 Alpha透明度效果</h3>

<ul>
<li>alpha透明用于那些背景会变化的情况</li>
<li>二进制透明需要一个更加创新的方法：设计色通过在图像周围添加一些和背景色相近的色块，来实现近视的透明效果。</li>
</ul>

<p><strong>圆角</strong></p>

<p>10.4.4 渐进增强png8 Alpha透明</p>

<h2 id="10-5-优化sprite">10.5 优化sprite</h2>

<h3 id="10-5-1-超级sprite-vs-模块化sprite">10.5.1 超级sprite vs 模块化Sprite</h3>

<p>网页多使用模块化
少则使用超级Sprite（合并成一张图片）</p>

<h3 id="10-5-2-高度优化的css-sprite">10.5.2 高度优化的CSS Sprite</h3>

<ul>
<li>按照颜色合并</li>
<li>避免不必要的空白</li>
<li>将元素水平排列，缩小Sprite</li>
<li>将颜色限制在256种以内，png8</li>
<li>先优化单独的图像，再优化Sprite</li>
<li>控制大小和对齐减少饭局吃像素的数量。</li>
<li>避免使用对角线渐变，无法被平铺</li>
<li>避免在IE6种使用alpha透明图像</li>
<li>每2－3个像素改变渐变的颜色，而不是每个像素都改变</li>
<li>处理logo的时候要小心，logo很易识别，就算非常小的修改也会很容易被注意到。</li>
</ul>

<h2 id="10-6其他图像优化方法">10.6其他图像优化方法</h2>

<h3 id="10-6-1-避免对图像进行缩放">10.6.1 避免对图像进行缩放</h3>

<p>使用合适的尺寸</p>

<h3 id="10-6-2-优化生成的图像">10.6.2 优化生成的图像</h3>

<h3 id="10-6-3-favicons">10.6.3 favicons</h3>

<ul>
<li>建立favicon，不管怎样，浏览器都会请求</li>
<li>添加Expires头</li>
<li>可以通过link标签制定路径</li>
<li>保持较小的图标大小</li>
<li>优化</li>
</ul>

<h3 id="10-6-4-apple触摸图标">10.6.4 Apple触摸图标</h3>

<p><code>&lt;link rel=&quot;apple-touch-icon&quot; href=&quot;http://CDN/name.png&quot;&gt;</code></p>

<p>iphone客户端只会在用户将页面添加到桌面的时候才会请求这个文件。</p>

<p>（补充：更多的格式、响应式）</p>

<h1 id="第12章-尽早刷新文档的输出">第12章 尽早刷新文档的输出</h1>

<h2 id="12-1-刷新文档头部的输出">12.1  刷新文档头部的输出</h2>

<p>HTML文档最先下载，浏览器会在html文档下载完毕后开始解析。</p>

<p>当生成html文档的时间过长时，才有必要使用，在html文档还未加载完之前就开始下载图片和外表脚本。</p>

<p>php flush()函数。</p>

<h2 id="12-2-输出缓冲">12.2 输出缓冲</h2>

<p>php 输出就是香stdout中写数据，而输出缓冲则在数据达到STDOUT之前建立另外一个队列。</p>

<h2 id="12-3-快数据">12.3 快数据</h2>

<p>http1.0 的响应是作为一整块数据返回的，它的大小是由<code>Content-Length</code>头来发送的，浏览器需要知道数据的大小，这样才能确定响应结束时间。开始渲染。</p>

<p>http1.1 引入<code>Transfer-Encoding:chunked</code>。通过快编码，html文档可以被分成多个数据块放回，每个响应的数据块都以标示其大小的指示符为开头。允许浏览器在下载数据包后马上进行解析，使得页面的加载速度更快。</p>

<p>通过快编码，服务器可以尽早发送响应，因为只需要知道每个发送快的大小即可。</p>

<p>通过<code>Trailer</code>头，块编码可以带来另外一个性能提升。</p>

<p>刷新输出：<code>Transfer-Encoding:chunked</code></p>

<h2 id="12-4-刷新输出和gzip压缩">12.4 刷新输出和Gzip压缩</h2>

<h1 id="第13章-少用iframe">第13章 少用iframe</h1>

<h1 id="第14章-简化css选择符">第14章 简化CSS选择符</h1>

<p>针对CSS的性能的最佳实践：</p>

<ul>
<li>把样式表放在文档HEAD标签中以提升页面的逐步渲染速度。</li>
<li>不要在IE中使用CSS表达式，因为它们可能会被执行成千上万次，从而导致打开页面的速度变慢。</li>
<li>避免使用过多的行内样式，因为这会增加下载页面内容的大小。</li>
</ul>

<p>另外一个关键的问题就是CSS选择符的开销。选择符由一系列初始化的参数组成，这些参数指明了要应用这个CSS规则的网页元素。虽然遵循准则对CSS选择符进行优化可以提升网站速度，<strong>但更重要的是，Web开发者应该避免一些常见且开销很大的CSS选择符模式。</strong></p>

<h2 id="14-1-选择符的类型">14.1 选择符的类型</h2>

<p>以下按照最简单到最复杂的顺序列出（主要讨论性能，暂不作具体介绍）</p>

<ul>
<li>ID选择符</li>
<li>类选择符</li>
<li>类型选择符</li>
<li>相邻兄弟选择符</li>
<li>之选择符</li>
<li>后代选择符</li>
<li>通配符选择符</li>
<li>属性选择符</li>
<li>伪类和伪元素</li>
</ul>

<h2 id="高效css选择符的关键">高效CSS选择符的关键</h2>

<p>通过编写高效的选择符来控制匹配耗时，实现高效选择符之路是从理解选择符匹配开始的。</p>

<h3 id="最右边优先">最右边优先</h3>

<p>看如下规则：</p>

<p><code>#toc &gt; li { font-weight: bold; }</code></p>

<p>我们中大多数人，尤其是那些从左到右阅读的人，可能猜想浏览器执行也是从左到右匹配规则的，因此会推测这条规则的开销不高。</p>

<p><strong>事实上，CSS选择符是从右到左进行匹配的。</strong>了解这方面知识后，我们知道这个之前看似高效的规则实际上开销相当高，浏览器必须遍历页面上面每个<strong>li</strong>元素确定其夫元素的id是否为<strong>toc</strong></p>

<p>前面提到的后代选择符示例甚至更糟：</p>

<p><code>#toc A { color: #444; }</code></p>

<p>如果浏览器是从左到右读取的，那么它仅仅需要检查toc里的链接元素，实际上却检查了整个文档中的每个链接。然而，浏览器并不仅仅检查每个链接的父元素，还要遍历文档树去查找id为toc的祖先元素。如果被评估的链接不是toc的后代，那么浏览器就要向上一级遍历直到文档的根结点。</p>

<blockquote>
<p>样式系统从最右的选择符开始向左匹配规则。只要当前选择符的左边还有其他选择符，样式系统就会继续向左移动，直到找到和规则匹配的元素，或者因为不匹配而退出。</p>
</blockquote>

<h3 id="编写高效的css选择符">编写高效的CSS选择符</h3>

<p>编写高效选择符的指南：</p>

<p><strong>避免使用通配符规则</strong></p>

<p>除了传统意义上的通配选择符之外，Hyatt也把相邻兄弟选择符、子选择符、后代选择符和属性选择符归纳到“通配规则”分类下。他推荐仅使用ID、类和标签选择符。</p>

<p><strong>不要限定ID选择符</strong></p>

<p>在页面中一个指定的ID只能对应一个元素，所以没必要添加额外的限定符。例如，div＃toc是没有必要的，应该简化为＃toc。</p>

<p><strong>不要先定类选择符</strong></p>

<p>不要用具体的标签先定类选择符，而是根据实际情况对类名进行扩张。例如，把<code>li.chapter</code> 改成<code>.li-chapter</code>,或是<code>.list-chapter</code>更好。</p>

<p><strong>让规则越具体越好</strong></p>

<p>不要试图编写向<code>ol li a</code>这样的长选择符，最好是创建一个像<code>.list-anchor</code>一样的类，并把它添加到适当的元素上。</p>

<p><strong>避免使用后代选择符</strong></p>

<p>通常处理后代选择符的开销是最高的，而使用子选择符可以得到想要的结果，并且更高效。</p>

<p><strong>避免使用标签－－子选择符</strong></p>

<p>如果有像<code>#toc &gt; li &gt; a</code>这样的基于标签的子选择符，那么应该使用一个类来关联每个标签元素，如<code>.toc-achor</code></p>

<p><strong>质疑子选择符的所有用途</strong></p>

<p>再次提醒大家检查所有使用子选择符的地方，然而尽可能用具体的类取代它们。</p>

<p><strong>依靠继承</strong></p>

<p>了解哪些属性可以通过继承而来，然而避免对这些属性重复指定规则。例如，对列表元素而不是每个列表项元素指定<code>list-style-image</code>.请参考继承属性的列表来了解每个元素可继承的属性。</p>

<h2 id="css选择符性能">CSS选择符性能</h2>

<p>选择符从右到左读取的发现激发很多人重写规则。最重要的是首先评估该问题的影响力，这可以确保我们把注意力集中在正确的问题上。</p>

<h3 id="复杂的选择符影响性能-有时">复杂的选择符影响性能（有时）</h3>

<p>书中经过测试研究表明，像子选择符和后代选择符这样比较复杂的CSS选择符并不总是影响页面性能，但这并不意味着我们不需要优化CSS选择符。在平时编写CSS时，某些类型的选择符对性能还是会有显著的影响。</p>

<h3 id="应避免使用的css选择符">应避免使用的CSS选择符</h3>

<p>测试后代选择符的例子：</p>

<p><code>div div div p a.class0007 { ... }</code></p>

<p>初看之下，这似乎是一个匹配开销很高的选择符，它是一个要匹配五级祖先元素的后代选择符。然而，回想一下选择符是从右到左匹配的，我们就会认识到这个后代选择符执行的速度和一个更简单的类选择符差不多。最右边的参数也叫<strong>关键选择符</strong>，它对浏览器执行的工作量起主要影响。
在本例中，关键选择符就是<code>a.class0007</code>, 页面中自由一个元素匹配这个关键选择符，所以匹配这个选择符所需要的时间是极少的。</p>

<p>反之，看看这条规则：</p>

<p><code>a.class0007 * { ... }</code></p>

<p>在这条规则中，关键选择符是 <code>＊</code>。它匹配所有的元素，所以浏览器必须检查每个元素是否为类名为<code>class0007</code>的链接元素的后代。</p>

<p>当决定对哪儿进行优化时，记住将重心放在那些肯能匹配大量元素的<strong>关键选择符</strong>上。不仅通配选择有这个问题，下面几个例子同样会消耗大量的时间加载页面：</p>

<p><code>a.class0007 div { ... }</code>
<code>#id0007 div { ... }</code>
<code>.class0007 [href] { ... }</code>
<code>div:first-child { ... }</code></p>

<h3 id="回流时间-reflow-time">回流时间（reflow time）</h3>

<p>对于Web2.0应用来说，更应考虑当用户和网页交互时，浏览器应用样式和布局元素所花费的时间，这又叫做<strong>回流时间</strong>。</p>

<p>当使用JavaScript修改DOM元素样式的某些属性时会触发回流。对于这个叫elem的DOM元素，下面的每行代码在大多数浏览器中都会触发回流：</p>

<pre><code class="language-js">	elem.className = &quot;newclass&quot;;
	elem.style.cssText = &quot;color:red&quot;;
	elem.style.paddind = &quot;8px&quot;;
	elem.style.display = &quot;&quot;;
</code></pre>

<p>这仅仅是一个子集，能触发回流的列表太长了。回流并不需要设计页面上的所有元素，浏览器已为此进行了优化，仅仅只对那些受回流影响的元素重新布局。如果elem是文档的body或其他一些有很多后代的元素，那么回流的开销一定相当高。</p>

<p>回流需要从新应用CSS规则，这意味着浏览器必须再次匹配所有的CSS选择符。如果CSS选择符是低效的，那么回流可能消耗的时间就会多到引起用户注意。</p>

<p>因此，对于杜绝低效CSS选择符的影响，不仅要考虑页面加载时间，也要考虑用户和Web2.0应用交互时如何使用样式进行表现，这一点非常重要。如果JavaScript对样式属性有操作，且网页开始变慢，那么低效的CSS选择符就很可能是罪魁祸首。</p>

<h2 id="在现实中测量css选择符">在现实中测量CSS选择符</h2>

<p>作者测试了站点AOL和Facebook，这两个网站使用了大量的规则，而且其中有很多是极端低效的，那么优化CSS选择符可以让网页更快。</p>

<p>编写高效的CSS选择符是要付出成本的：将每个受影响元素的后代选择符替换成类选择符，不仅会增加页面大小，还会降低样式的灵活性。
最需要修正的选择符是那些可以匹配大量元素的关键选择符（最右边的选择符）。虽然性能提升的益处多种多样，但Web开发者应该避免使用会影响网页性能的CSS选择符。</p>

<h1 id="性能工具">性能工具</h1>

<ul>
<li>数据包嗅探器</li>
<li>Web开发工具</li>
<li>性能分析器</li>
<li>其他</li>
</ul>

<h2 id="数据包嗅探器">数据包嗅探器</h2>

<p>查看页面加载的过程。
<strong>HttpWatch</strong>
<a href="http://www.httpwatch.com/download/">HttpWatch</a></p>

<p>（支持Windows 和 ios）</p>

<p><strong>Firebug网络控制面板</strong></p>

<p><strong>AOL Pagetest</strong></p>

<p><a href="http://pagetest.wiki.sourceforge.net">aol</a> ie插件</p>

<p><strong>VRTA</strong></p>

<p><strong>IBM Page Detailer</strong></p>

<p><strong>Web Inspector</strong></p>

<p><strong>fiddler</strong></p>

<p><strong>charles</strong>
<strong>wireshar</strong></p>

<h2 id="web开发工具">Web开发工具</h2>

<ul>
<li>firebug</li>
<li>web inspector</li>
<li>IE Developer Toolbar</li>
</ul>

<h2 id="性能分析器">性能分析器</h2>

<p><strong>YSlow</strong></p>

<p><strong>AOL Pagetest</strong></p>

<p><strong>VRTA</strong></p>

<p><strong>Hammerhead</strong></p>

<p><strong>Smush.it</strong></p>

<p>提供了分析和优化网页中图片的服务</p>

<p><strong>Cuzillion</strong></p>

<p>性能边界情况？</p>

<p><strong>UA Profiler</strong></p>

<p>浏览器性能测试集合。</p>

  </div>
</div>
<div class="container has-text-centered">
    
</div>

<div class="container has-text-centered">
  
</div>
<section class="section">
  <div class="container has-text-centered">
    <p></p>
  </div>
</section>


